package com.chu.cloud.service.impl;

import com.chu.cloud.dto.*;
import com.chu.cloud.dto.order.BaseOrderCreateDto;
import com.chu.cloud.dto.order.CommonOrderCreateDto;
import com.chu.cloud.dto.order.OrderItemDto;
import com.chu.cloud.dto.order.OrderResult;
import com.chu.cloud.entity.MerchantOrder;
import com.chu.cloud.entity.OrderDetail;
import com.chu.cloud.enums.OrderStatusEnums;
import com.chu.cloud.feign.client.IProductFeignClient;
import com.chu.cloud.feign.client.IUserFeignClient;
import com.chu.cloud.rabbit.dead.DelayConstant;
import com.chu.cloud.rabbit.dead.DelayMessagePayload;
import com.chu.cloud.rabbit.fanout.send.RabbitFanoutSender;
import com.chu.cloud.repository.MerchantOrderRepository;
import com.chu.cloud.repository.OrderDetailRepository;
import com.chu.cloud.response.ResponseMessage;
import com.chu.cloud.service.base.AbstractOrderService;
import com.chu.cloud.util.ChuException;
import com.chu.cloud.util.JsonUtils;
import com.chu.cloud.vo.MemberCouponVo;
import com.chu.cloud.vo.ProductVo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @Description:
 * @author: TianShu.CHU
 * @CreateDate: 2018-08-09 21:56
 * @Version: 1.0
 */
@Service("commonOrder")
@Slf4j
public class CommonOrderServiceImpl extends AbstractOrderService {

    @Autowired
    private IProductFeignClient productFeignClient;

    @Autowired
    private OrderDetailRepository orderDetailRepository;

    @Autowired
    private MerchantOrderRepository orderRepository;

    @Autowired
    private RabbitFanoutSender fanoutSender;

    @Autowired
    private IUserFeignClient userFeignClient;

    @Autowired
    private ShoppingCartServiceImpl shoppingCartService;

    /**
     * 创建订单
     *
     * @param userId             用户Id
     * @param baseOrderCreateDto 创建订单参数
     * @return 返回一个包含用户所购买的且以店铺为单位的订单详情列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderResult generateOrder(Integer userId, BaseOrderCreateDto baseOrderCreateDto) {
        CommonOrderCreateDto orderCreateDto = (CommonOrderCreateDto) baseOrderCreateDto;
        List<OrderDetailDto> result = Lists.newArrayList();
        List<OrderItemDto> goodsList = orderCreateDto.getGoodsList();
        withOrderProductId(goodsList);
        //计算店铺订单价格
        Map<Integer, BigDecimal> shopOrderPriceMap = goodsList.stream().collect(Collectors.groupingBy(OrderItemDto::getShopId,
                Collectors.reducing(BigDecimal.ZERO, OrderItemDto::getItemPrice, BigDecimal::add)));
        ResponseMessage<List<MemberCouponDto>> response = userFeignClient.findByIdIn(orderCreateDto.getMemberCoupons().stream().map(c -> c.getId()).collect(toList()));
        Map<Integer, List<MemberCouponVo>> shopCouponMap = new HashMap<>(16);
        if (response.getCode() == 200) {
            List<MemberCouponVo> couponVoList = shoppingCartService.mergeCoupons(response.getData());
            shopCouponMap = couponVoList.stream().collect(Collectors.groupingBy(MemberCouponVo::getShopId));
        }
        Map<Integer, List<OrderItemDto>> shopGoodsMap = goodsList.stream().collect(Collectors.groupingBy(OrderItemDto::getShopId));
        for (Map.Entry<Integer, List<OrderItemDto>> entry : shopGoodsMap.entrySet()) {
            Integer shopId = entry.getKey();
            String orderNo = generateOrderNo(orderCreateDto.getOrderType(), shopId);
            List<OrderItemDto> itemsList = entry.getValue();
            BigDecimal shopOrderAmount = shopOrderPriceMap.get(shopId);
            BigDecimal shopDiscountPrice = new BigDecimal(0);
            List<MemberCouponVo> couponList = shopCouponMap.get(shopId);
            if (couponList != null) {
                //这个版本先不做叠加
                MemberCouponVo memberCouponVo = couponList.get(0);
                if (shopOrderAmount.compareTo(memberCouponVo.getConditionMoney()) >= 0) {
                    shopDiscountPrice = memberCouponVo.getDiscountMoney();
                }
            }
            //订单详情入库
            for (OrderItemDto itemDto : itemsList) {
                OrderDetail orderDetail = super.packageOrderDetail(userId, orderNo, shopId, itemDto.getProductId(), itemDto.getQuantity(), itemDto.getProductPrice());
                orderDetailRepository.save(orderDetail);
            }
            MerchantOrder order = super.packageOrder(userId, shopId, orderCreateDto, orderNo);
            order.setTotalPrice(shopOrderAmount);
            order.setPayPrice(shopOrderAmount.subtract(shopDiscountPrice));
            ResponseMessage<List<ProductPointPlanDto>> responseMessage = productFeignClient.reserveProduct(itemsList);
            if (responseMessage.getCode() != 200) {
                //预留订单商品失败,回滚订单详情
                //如果第一家店铺预留库存成功,第二家库存不足,第一家店铺预留的库存不会回滚,
                //解决办法:预留不扣减库存,当用户下单全部成功之后发消息进行真正扣减
                throw new ChuException(responseMessage.getMessage());
            }
            //商品预留成功将订单状态置为已确认
            order.setOrderStatus(OrderStatusEnums.CONFIRM);
            List<ProductPointPlanDto> pointPlanDtos = responseMessage.getData();
            //计算可获取的积分数
            int rewardPoint = pointPlanDtos.stream().mapToInt(ProductPointPlanDto::getRewardPoint).sum();
            order.setRewardPoints(rewardPoint);
            MerchantOrder platOrder = orderRepository.save(order);
            //发送延迟队列,30分钟未支付关闭订单
            OrderDelayPay delayPay = new OrderDelayPay(orderNo,userId,orderCreateDto.getOrderType().getValue());
            DelayMessagePayload payload = new DelayMessagePayload(DelayConstant.FanoutQueue.ORDER_DELAY_PAY,
                    DelayConstant.FanoutExchange.ORDER_DELAY_PAY_DEAD, DelayConstant.FanoutQueue.ORDER_DELAY_PAY_DEAD,
                    JsonUtils.obj2json(delayPay), 30 * 60 * 1000);
            fanoutSender.sendDelayMessage(payload);
            //返回数据
            packageReturn(result, platOrder);
        }
        UserDetail userDetail = super.userDetail(orderCreateDto.getAddressId(), orderCreateDto.getMemberId());
        AddressDto addressDto = new AddressDto(userDetail.getReceiveUserName(), userDetail.getReceiveUserPhone(), userDetail.getAddress());
        OrderResult orderResult = new OrderResult(addressDto, result);
        return orderResult;
    }

    private void packageReturn(List<OrderDetailDto> result, MerchantOrder platOrder) {
        OrderDetailDto orderDetailDto = new OrderDetailDto();
        orderDetailDto.setTotalPrice(platOrder.getTotalPrice());
        orderDetailDto.setPayPrice(platOrder.getPayPrice());
        orderDetailDto.setDiscountPrice(platOrder.getTotalPrice().subtract(platOrder.getPayPrice()));
        orderDetailDto.setOrderNo(platOrder.getOrderNo());
        orderDetailDto.setOrderTime(platOrder.getCreatedDate());
        result.add(orderDetailDto);
    }

    private void withOrderProductId(List<OrderItemDto> goodsList) {
        List<Integer> productIds = goodsList.stream().map(OrderItemDto::getProductId).collect(toList());
        ResponseMessage<List<ProductVo>> response = productFeignClient.findByIdIn(productIds);
        List<ProductVo> productVos = response.getData();
        pack(goodsList, productVos);
    }

    private void pack(List<OrderItemDto> goodsList, List<ProductVo> productVos) {
        for (ProductVo productVo : productVos) {
            for (OrderItemDto itemDto : goodsList) {
                if (productVo.getId().equals(itemDto.getProductId())) {
                    itemDto.setProductPrice(productVo.getPrice());
                }
            }
        }
    }


}
